package com.stox.dto.enumeration;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;

import com.stox.dto.AbstractBar;
import com.stox.dto.Bar;

public enum SpanType {
	MINUTELY_1(Calendar.MINUTE, 1, "Minutely_1"), 
	MINUTELY_5(Calendar.MINUTE, 5, "Minutely_5"), 
	MINURELY_15(Calendar.MINUTE, 15, "Minutely_15"), 
	HALF_HOURLY(Calendar.MINUTE, 30, "HalfHourly"), 
	HOURLY(Calendar.HOUR, 1, "Hourly"), 
	DAILY(Calendar.DATE, 1, "Daily"), 
	WEEKLY(Calendar.WEEK_OF_YEAR, 1, "Weekly"), 
	MONTHLY(Calendar.MONTH, 1, "Monthly");

	private final int unit;
	private final int count;
	private final String code;

	private SpanType(int unit, int count, String code) {
		this.unit = unit;
		this.count = count;
		this.code = code;
	}
	
	
	public void merge(List<AbstractBar> higherBars, AbstractBar bar){
		
		int value = -1;
		AbstractBar higherBar = null;
		Calendar calendar = Calendar.getInstance();
		
		if(!higherBars.isEmpty()){
			higherBar = higherBars.get(higherBars.size() - 1);
			calendar.setTime(higherBar.getDate());
			value = calendar.get(getUnit());
		}
		
		calendar.setTime(bar.getDate());
		if(value != calendar.get(getUnit())){
			higherBar = new Bar();
			higherBar.setOpen(bar.getOpen());
			higherBars.add(higherBar);
		}

		if(bar.getHigh() > higherBar.getHigh()){
			higherBar.setHigh(bar.getHigh());
		}
		if(bar.getLow() < higherBar.getLow()){
			higherBar.setLow(bar.getLow());
		}
		higherBar.setClose(bar.getClose());
		higherBar.setDate(bar.getDate());
		higherBar.setVolume(bar.getVolume() + higherBar.getVolume());
	}
	
	public List<AbstractBar> merge(List<AbstractBar> bars){
		if(null == bars || bars.isEmpty()) return bars;
		Calendar calendar = Calendar.getInstance();
		List<AbstractBar> higherBars = new ArrayList<AbstractBar>();
		int value = -1;
		AbstractBar higherBar = null;
		
		for(AbstractBar bar : bars){
			calendar.setTime(bar.getDate());
			if(value != calendar.get(getUnit())){
				higherBar = new Bar();
				higherBar.setOpen(bar.getOpen());
				higherBar.setHigh(Double.MIN_VALUE);
				higherBar.setLow(Double.MAX_VALUE);
				higherBars.add(higherBar);
				value = calendar.get(getUnit());
			}
			
			if(bar.getHigh() > higherBar.getHigh()){
				higherBar.setHigh(bar.getHigh());
			}
			if(bar.getLow() < higherBar.getLow()){
				higherBar.setLow(bar.getLow());
			}
			higherBar.setClose(bar.getClose());
			higherBar.setDate(bar.getDate());
			higherBar.setVolume(bar.getVolume() + higherBar.getVolume());
		}
		
		//There is no way to find out if last bar was fully formed with available data, thus discard it
		if(!higherBars.isEmpty()){
			higherBars.remove(higherBars.size()-1);
		}
		return higherBars;
	}
	
	public SpanType up(){
		if(ordinal() == (values().length -1))
			return null;
		else
			return values()[ordinal() + 1];
	}
	
	public SpanType down(){
		if(ordinal() == 0)
			return null;
		else
			return values()[ordinal() - 1];
	}
	
	//TODO needs re-write, does not take care of anything below DAILY
	public List<AbstractBar> up(List<AbstractBar> bars){
		if(null == bars || bars.isEmpty()) return bars;
		SpanType higher = up();
		
		if(null == higher) return null;
		Calendar calendar = Calendar.getInstance();
		List<AbstractBar> higherBars = new ArrayList<AbstractBar>();
		int value = -1;
		AbstractBar higherBar = null;
		for(AbstractBar bar : bars){
			calendar.setTime(bar.getDate());
			if(value != calendar.get(higher.getUnit())){
				higherBar = new Bar();
				higherBar.setOpen(bar.getOpen());
				higherBars.add(higherBar);
				value = calendar.get(higher.getUnit());
			}
			
			if(bar.getHigh() > higherBar.getHigh()){
				higherBar.setHigh(bar.getHigh());
			}
			if(bar.getLow() < higherBar.getLow()){
				higherBar.setLow(bar.getLow());
			}
			higherBar.setClose(bar.getClose());
			higherBar.setDate(bar.getDate());
			higherBar.setVolume(bar.getVolume() + higherBar.getVolume());
		}
		
		return higherBars;
	}

	public int getCount() {
		return count;
	}

	public int getUnit() {
		return unit;
	}

	public String getCode() {
		return code;
	}
	
	@Override
	public String toString() {
		return getCode();
	}
	
}
